/**
 * Copyright © 2016-2025 The Thingsboard Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.terracloud.server.service.log;

import com.terracloud.server.common.data.log.TerminalLog;
import com.terracloud.server.common.data.id.DeviceId;
import com.terracloud.server.common.data.id.TenantId;
import com.terracloud.server.common.data.id.TerminalLogId;
import com.terracloud.server.common.data.log.LogLevel;
import com.terracloud.server.common.data.log.LogType;
import com.terracloud.server.common.data.log.LogStatus;
import com.terracloud.server.common.data.log.TerminalStatistics;
import com.terracloud.server.common.data.page.TimePageLink;
import com.terracloud.server.dao.log.TerminalLogDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;

/**
 * 终端日志服务默认实现
 */
@Service
@Slf4j
public class DefaultTerminalLogService implements TerminalLogService {

    @Autowired
    private TerminalLogDao terminalLogDao;

    @Override
    @Transactional
    public TerminalLog saveTerminalLog(TerminalLog terminalLog) {
        log.trace("Executing saveTerminalLog [{}]", terminalLog);
        return terminalLogDao.save(terminalLog);
    }

    @Override
    @Transactional(readOnly = true)
    public TerminalLog findTerminalLogById(TerminalLogId terminalLogId) {
        log.trace("Executing findTerminalLogById [{}]", terminalLogId);
        return terminalLogDao.findById(terminalLogId);
    }

    @Override
    @Transactional
    public void deleteTerminalLog(TerminalLogId terminalLogId) {
        log.trace("Executing deleteTerminalLog [{}]", terminalLogId);
        terminalLogDao.removeById(terminalLogId);
    }

    @Override
    @Transactional(readOnly = true)
    public com.terracloud.server.common.data.page.PageData<TerminalLog> findTerminalLogsByDeviceId(TenantId tenantId, DeviceId deviceId, TimePageLink pageLink) {
        log.trace("Executing findTerminalLogsByDeviceId [{}][{}]", tenantId, deviceId);
        log.debug("Service: Finding terminal logs by tenantId={} and deviceId={} with pageLink={}", tenantId, deviceId, pageLink);
        com.terracloud.server.common.data.page.PageData<TerminalLog> result = terminalLogDao.findByDeviceId(tenantId, deviceId, pageLink);
        log.debug("Service: Found {} terminal logs", result.getTotalElements());
        return result;
    }

    @Override
    @Transactional(readOnly = true)
    public com.terracloud.server.common.data.page.PageData<TerminalLog> findTerminalLogsByTenantId(TenantId tenantId, TimePageLink pageLink) {
        log.trace("Executing findTerminalLogsByTenantId [{}]", tenantId);
        log.debug("Service: Finding terminal logs by tenantId={} with pageLink={}", tenantId, pageLink);
        com.terracloud.server.common.data.page.PageData<TerminalLog> result = terminalLogDao.findByTenantId(tenantId, pageLink);
        log.debug("Service: Found {} terminal logs", result.getTotalElements());
        return result;
    }

    @Override
    @Transactional(readOnly = true)
    public com.terracloud.server.common.data.page.PageData<TerminalLog> findTerminalLogsByTenantIdAndType(TenantId tenantId, LogType logType, TimePageLink pageLink) {
        log.trace("Executing findTerminalLogsByTenantIdAndType [{}][{}]", tenantId, logType);
        log.debug("Service: Finding terminal logs by tenantId={} and logType={} with pageLink={}", tenantId, logType, pageLink);
        com.terracloud.server.common.data.page.PageData<TerminalLog> result = terminalLogDao.findByTenantIdAndType(tenantId, logType, pageLink);
        log.debug("Service: Found {} terminal logs", result.getTotalElements());
        return result;
    }

    @Override
    @Transactional(readOnly = true)
    public com.terracloud.server.common.data.page.PageData<TerminalLog> findTerminalLogsByTenantIdAndLevel(TenantId tenantId, LogLevel logLevel, TimePageLink pageLink) {
        log.trace("Executing findTerminalLogsByTenantIdAndLevel [{}][{}]", tenantId, logLevel);
        log.debug("Service: Finding terminal logs by tenantId={} and logLevel={} with pageLink={}", tenantId, logLevel, pageLink);
        com.terracloud.server.common.data.page.PageData<TerminalLog> result = terminalLogDao.findByTenantIdAndLevel(tenantId, logLevel, pageLink);
        log.debug("Service: Found {} terminal logs", result.getTotalElements());
        return result;
    }

    @Override
    @Transactional(readOnly = true)
    public com.terracloud.server.common.data.page.PageData<TerminalLog> findTerminalLogsByTenantIdAndDeviceIdAndType(TenantId tenantId, DeviceId deviceId, LogType logType, TimePageLink pageLink) {
        log.trace("Executing findTerminalLogsByTenantIdAndDeviceIdAndType [{}][{}][{}]", tenantId, deviceId, logType);
        log.debug("Service: Finding terminal logs by tenantId={}, deviceId={} and logType={} with pageLink={}", tenantId, deviceId, logType, pageLink);
        com.terracloud.server.common.data.page.PageData<TerminalLog> result = terminalLogDao.findByTenantIdAndDeviceIdAndType(tenantId, deviceId, logType, pageLink);
        log.debug("Service: Found {} terminal logs", result.getTotalElements());
        return result;
    }

    @Override
    @Transactional(readOnly = true)
    public com.terracloud.server.common.data.page.PageData<TerminalLog> findTerminalLogsByTenantIdAndDeviceIdAndLevel(TenantId tenantId, DeviceId deviceId, LogLevel logLevel, TimePageLink pageLink) {
        log.trace("Executing findTerminalLogsByTenantIdAndDeviceIdAndLevel [{}][{}][{}]", tenantId, deviceId, logLevel);
        log.debug("Service: Finding terminal logs by tenantId={}, deviceId={} and logLevel={} with pageLink={}", tenantId, deviceId, logLevel, pageLink);
        com.terracloud.server.common.data.page.PageData<TerminalLog> result = terminalLogDao.findByTenantIdAndDeviceIdAndLevel(tenantId, deviceId, logLevel, pageLink);
        log.debug("Service: Found {} terminal logs", result.getTotalElements());
        return result;
    }

    @Override
    @Transactional(readOnly = true)
    public long getTodayAlertCount(TenantId tenantId) {
        log.trace("Executing getTodayAlertCount [{}]", tenantId);
        // 计算今天的开始和结束时间
        LocalDate today = LocalDate.now();
        long startTime = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant()).getTime();
        long endTime = Date.from(today.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant()).getTime();
        
        TimePageLink pageLink = new TimePageLink(1, 0, null, null, startTime, endTime);
        com.terracloud.server.common.data.page.PageData<TerminalLog> pageData = 
            terminalLogDao.findByTenantIdAndType(tenantId, LogType.ALERT_LOG, pageLink);
        
        return pageData.getTotalElements();
    }

    @Override
    @Transactional(readOnly = true)
    public long getUnprocessedWarningCount(TenantId tenantId) {
        log.trace("Executing getUnprocessedWarningCount [{}]", tenantId);
        return terminalLogDao.countByProcessStatus(tenantId, LogStatus.UNPROCESSED);
    }

    @Override
    @Transactional(readOnly = true)
    public long getCriticalAlertCount(TenantId tenantId) {
        log.trace("Executing getCriticalAlertCount [{}]", tenantId);
        return terminalLogDao.countByCritical(tenantId, true);
    }

    @Override
    @Transactional(readOnly = true)
    public double getSlaComplianceRate(TenantId tenantId) {
        log.trace("Executing getSlaComplianceRate [{}]", tenantId);
        // 这里只是一个示例实现，实际应该根据业务逻辑计算SLA达标率
        // 比如：(总日志数 - 超时日志数) / 总日志数 * 100
        long totalCount = terminalLogDao.findByTenantId(tenantId, new TimePageLink(1, 0, null, null, null, null)).getTotalElements();
        long timeoutCount = terminalLogDao.countByDurationGreaterThan(tenantId, 86400000L); // 24小时
        
        if (totalCount == 0) {
            return 100.0;
        }
        
        return ((double)(totalCount - timeoutCount) / totalCount) * 100;
    }

    @Override
    @Transactional(readOnly = true)
    public long getTerminalExceptionCount(TenantId tenantId) {
        log.trace("Executing getTerminalExceptionCount [{}]", tenantId);
        TimePageLink pageLink = new TimePageLink(1, 0, null, null, null, null);
        com.terracloud.server.common.data.page.PageData<TerminalLog> pageData = 
            terminalLogDao.findByTenantIdAndType(tenantId, LogType.RECEIVE_EXCEPTION_LOG, pageLink);
        
        return pageData.getTotalElements();
    }

    @Override
    @Transactional(readOnly = true)
    public long getLongTermExceptionCount(TenantId tenantId) {
        log.trace("Executing getLongTermExceptionCount [{}]", tenantId);
        return terminalLogDao.countByDurationGreaterThan(tenantId, 86400000L); // 24小时
    }

    @Override
    @Transactional(readOnly = true)
    public TerminalStatistics getTerminalStatistics(TenantId tenantId) {
        log.trace("Executing getTerminalStatistics [{}]", tenantId);
        long todayAlertCount = getTodayAlertCount(tenantId);
        long unprocessedWarningCount = getUnprocessedWarningCount(tenantId);
        long criticalAlertCount = getCriticalAlertCount(tenantId);
        double slaComplianceRate = getSlaComplianceRate(tenantId);
        long terminalExceptionCount = getTerminalExceptionCount(tenantId);
        long longTermExceptionCount = getLongTermExceptionCount(tenantId);
        
        return new TerminalStatistics(todayAlertCount, unprocessedWarningCount, 
                criticalAlertCount, slaComplianceRate, terminalExceptionCount, longTermExceptionCount);
    }
}